package org.kugua.strategy.context;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.kugua.dto.Captcha;
import org.kugua.effect.IEffect;
import org.kugua.effect.impl.AggressorLineEffect;
import org.kugua.effect.impl.BesselLineEffect;
import org.kugua.effect.impl.OvalEffect;
import org.kugua.enums.CaptchaEnum;
import org.kugua.processor.IPreProcessor;
import org.kugua.processor.impl.BackgroundImageProcessor;
import org.kugua.strategy.CaptchaStrategy;
import org.kugua.strategy.impl.*;
import org.kugua.utils.RandomUtils;
import org.springframework.util.Assert;

import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * CaptchaContextStrategy
 *
 * @author 苦瓜
 * @create 2024/9/10 23:00
 * @since 1.0.0
 */
@Slf4j
public class CaptchaContextStrategy {

    private static final Map<String, CaptchaStrategy> strategyMap;

    static {
        strategyMap = new HashMap<>();
        // 光圈干扰器
        OvalEffect unFillOval = new OvalEffect();
        unFillOval.setOvalNum(15);
        unFillOval.setFill(false);
        // 点触式策略
        ClickTouchCaptchaStrategy clickTouchCaptchaStrategy = new ClickTouchCaptchaStrategy();
        IPreProcessor backgroundImageProcessor = new BackgroundImageProcessor();
        List<IPreProcessor> iProcessors = List.of(backgroundImageProcessor);
        clickTouchCaptchaStrategy.setPreProcess(iProcessors);
        clickTouchCaptchaStrategy.setEffects(List.of(unFillOval));
        strategyMap.put(CaptchaEnum.CLICK_TOUCH.getType(), clickTouchCaptchaStrategy);
        // 文本类策略
        TextCaptchaStrategy textCaptchaStrategy = new TextCaptchaStrategy();
        OvalEffect fillOval = new OvalEffect();
        fillOval.setOvalNum(15);
        fillOval.setFill(true);
        BesselLineEffect besselLineEffect = new BesselLineEffect();
        besselLineEffect.setNum(10);
        AggressorLineEffect aggressorLineProcessor = new AggressorLineEffect();
        List<IEffect> effects = Arrays.asList(unFillOval, fillOval, besselLineEffect, aggressorLineProcessor);
        textCaptchaStrategy.setEffects(effects);
        strategyMap.put(CaptchaEnum.TEXT.getType(), textCaptchaStrategy);
        // 滑动类策略
        SliderCaptchaStrategy2 sliderCaptchaStrategy = new SliderCaptchaStrategy2();
        strategyMap.put(CaptchaEnum.SLIDE.getType(), sliderCaptchaStrategy);
        // 问答类策略
        QuestionAndAnswerCaptchaStrategy questionAndAnswerCaptchaStrategy = new QuestionAndAnswerCaptchaStrategy();
        questionAndAnswerCaptchaStrategy.setEffects(effects);
        strategyMap.put(CaptchaEnum.QAC.getType(), questionAndAnswerCaptchaStrategy);
    }

    private volatile static CaptchaContextStrategy instance;

    /**
     * 获取实例对象(双重校验锁)
     *
     * @return CaptchaContextStrategy
     */
    public static CaptchaContextStrategy getInstance() {
        if (Objects.isNull(instance)) {
            synchronized (CaptchaContextStrategy.class) {
                if (Objects.isNull(instance)) {
                    instance = new CaptchaContextStrategy();
                }
            }
        }
        return instance;
    }

    private CaptchaContextStrategy() {
    }

    public Captcha generate() {
        return this.generate(null);
    }

    /**
     * 验证码-生成
     *
     * @param type 验证码类型
     * @return Captcha
     */
    public Captcha generate(String type) {
        return this.generate(type, 400, 200);
    }

    /**
     * 验证码-生成
     *
     * @param type   验证码类型
     * @param width  宽度
     * @param height 高度
     * @return Captcha
     */
    public Captcha generate(String type, int width, int height) {
        return this.generate(type, width, height, null);
    }

    /**
     * 验证码生成
     *
     * @param type   验证码类型
     * @param width  宽度
     * @param height 高度
     * @param words  内容
     * @return Captcha
     */
    public Captcha generate(String type, int width, int height, String words) {
        return this.generate(type, width, height, words, null);
    }

    /**
     * 验证码生成
     *
     * @param type 验证码类型
     * @param width  宽度
     * @param height 高度
     * @param words  验证码内容
     * @param font   验证码字体
     * @return Captcha
     */
    public Captcha generate(String type, int width, int height, String words, Font font) {
        String finType = Optional.ofNullable(type).orElseGet(() -> {
            List<String> types = new ArrayList<>(strategyMap.keySet());
            Integer random = RandomUtils.random(types.size());
            return types.get(random);
        });
        CaptchaStrategy captchaStrategy = strategyMap.get(finType);
        if (Objects.isNull(captchaStrategy)) {
            throw new RuntimeException("type not support.");
        }
        return captchaStrategy.generate(width, height, words, font);
    }

    /**
     * 验证码校验
     *
     * @param type 验证码类型
     * @param source 原始值
     * @param target 目标值
     * @return boolean 校验结果
     */
    public boolean valid(String type, List<String> source, List<String> target) {
        return this.valid(type, source, target, 10L);
    }

    /**
     * 验证码校验
     *
     * @param type 类型
     * @param source 原始值
     * @param target 目标值
     * @param accuracy 精度(滑块类、点触类使用)
     * @return boolean 校验结果
     */
    public boolean valid(String type, List<String> source, List<String> target, Long accuracy) {
        log.info("captcha type: {}, source: {}, target:{}, accuracy: {}",
                type, JSON.toJSONString(source), JSON.toJSONString(target), accuracy);
        Assert.notEmpty(source, "captcha source can not empty.");
        boolean isSupportType = strategyMap.containsKey(type);
        if (!isSupportType) {
            return false;
        }
        CaptchaStrategy captchaStrategy = strategyMap.get(type);
        return captchaStrategy.valid(source, target, accuracy);
    }
}
